from django.apps import apps
from rest_framework import exceptions
from django.core.cache import cache
from libs.auth.token import get_user_token_key, generate_token
from account.models import UserRole


class UserService:
    def __init__(self):
        self.model = apps.get_model('account', 'User')
        self.manager = self.model.objects

    def get(self, user_id):
        return self.manager.filter(id=user_id).first()

    def login(self, username, password):
        user = self.manager.filter(username=username).first()
        if not user:
            raise exceptions.ValidationError({'error': '用户名或密码有误'})
        if not user.check_password(password):
            raise exceptions.ValidationError({'error': '用户名或密码有误'})
        token = self.set_token(user.id)
        return user, token

    def logout(self, token):
        cache.delete(get_user_token_key(token))

    def set_token(self, user_id):
        token = generate_token()
        expire_seconds = 60 * 60 * 24 * 15
        cache.set(get_user_token_key(token), user_id, expire_seconds)
        return token

    def exists(self, username):
        return self.manager.filter(username=username).exists()

    def create(self, data):
        user = self.model(
            username=data['username'],
            name=data['name'],
        )
        user.set_password(data['password'])
        user.save()
        return user

    def update_roles(self, user, role_ids):
        cur_role_ids = UserRole.objects.filter(user_id=user.id).values_list('role_id', flat=True)
        deleted_role_ids = set(cur_role_ids) - set(role_ids)
        added_role_ids = set(role_ids) - set(cur_role_ids)
        UserRole.objects.filter(user_id=user.id, role_id__in=deleted_role_ids).delete()
        instances = []
        for added_role_id in added_role_ids:
            instance = UserRole(
                user_id=user.id,
                role_id=added_role_id
            )
            instances.append(instance)
        UserRole.objects.bulk_create(instances)


user_service = UserService()
